home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / misc / ispell-3.001 / ispell-3~ / ispell-3.1 / ispell.c < prev    next >
C/C++ Source or Header  |  1995-10-12  |  27KB  |  1,007 lines

  1. #ifndef lint
  2. static char Rcs_Id[] =
  3.     "$Id: ispell.c,v 1.133 1995/10/11 04:30:29 geoff Exp $";
  4. #endif
  5.  
  6. #define MAIN
  7.  
  8. /*
  9.  * ispell.c - An interactive spelling corrector.
  10.  *
  11.  * Copyright (c), 1983, by Pace Willisson
  12.  *
  13.  * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
  14.  * All rights reserved.
  15.  *
  16.  * Redistribution and use in source and binary forms, with or without
  17.  * modification, are permitted provided that the following conditions
  18.  * are met:
  19.  *
  20.  * 1. Redistributions of source code must retain the above copyright
  21.  *    notice, this list of conditions and the following disclaimer.
  22.  * 2. Redistributions in binary form must reproduce the above copyright
  23.  *    notice, this list of conditions and the following disclaimer in the
  24.  *    documentation and/or other materials provided with the distribution.
  25.  * 3. All modifications to the source code must be clearly marked as
  26.  *    such.  Binary redistributions based on modified source code
  27.  *    must be clearly marked as modified versions in the documentation
  28.  *    and/or other materials provided with the distribution.
  29.  * 4. All advertising materials mentioning features or use of this software
  30.  *    must display the following acknowledgment:
  31.  *      This product includes software developed by Geoff Kuenning and
  32.  *      other unpaid contributors.
  33.  * 5. The name of Geoff Kuenning may not be used to endorse or promote
  34.  *    products derived from this software without specific prior
  35.  *    written permission.
  36.  *
  37.  * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
  38.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  39.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  40.  * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
  41.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  42.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  43.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  44.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  45.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  46.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47.  * SUCH DAMAGE.
  48.  */
  49.  
  50. /*
  51.  * $Log: ispell.c,v $
  52.  * Revision 1.133  1995/10/11  04:30:29  geoff
  53.  * Get rid of an unused variable.
  54.  *
  55.  * Revision 1.132  1995/08/05  23:19:36  geoff
  56.  * If the DICTIONARY environment variable is set, derive the default
  57.  * personal-dictionary name from it.
  58.  *
  59.  * Revision 1.131  1995/01/08  23:23:39  geoff
  60.  * Support variable hashfile suffixes for DOS purposes.  Report all the
  61.  * new configuration variables in the -vv switch.  Do some better error
  62.  * checking for mktemp failures.  Support the rename system call.  All of
  63.  * this is to help make DOS porting easier.
  64.  *
  65.  * Revision 1.130  1995/01/03  19:24:08  geoff
  66.  * When constructing a personal-dictioary name from the hash file name,
  67.  * don't stupidly include path directory components.
  68.  *
  69.  * Revision 1.129  1995/01/03  02:23:19  geoff
  70.  * Disable the setbuf call on BSDI systems, sigh.
  71.  *
  72.  * Revision 1.128  1994/10/26  05:12:28  geoff
  73.  * Include boundary characters in the list of characters to be tried in
  74.  * corrections.
  75.  *
  76.  * Revision 1.127  1994/10/25  05:46:07  geoff
  77.  * Allow the default dictionary to be specified by an environment
  78.  * variable (DICTIONARY) as well as a switch.
  79.  *
  80.  * Revision 1.126  1994/09/16  03:32:34  geoff
  81.  * Issue an error message for bad affix flags
  82.  *
  83.  * Revision 1.125  1994/07/28  05:11:36  geoff
  84.  * Log message for previous revision: fix backup-file checks to correctly
  85.  * test for exceeding MAXNAMLEN.
  86.  *
  87.  * Revision 1.124  1994/07/28  04:53:39  geoff
  88.  *
  89.  * Revision 1.123  1994/05/17  06:44:12  geoff
  90.  * Add support for controlled compound formation and the COMPOUNDONLY
  91.  * option to affix flags.
  92.  *
  93.  * Revision 1.122  1994/04/27  01:50:37  geoff
  94.  * Print MAX_CAPS in -vv mode.
  95.  *
  96.  * Revision 1.121  1994/03/16  03:49:10  geoff
  97.  * Fix -vv to display the value of NO_STDLIB_H.
  98.  *
  99.  * Revision 1.120  1994/03/15  06:24:28  geoff
  100.  * Allow the -t, -n, and -T switches to override each other, as follows:
  101.  * if no switches are given, the deformatter and string characters are
  102.  * chosen based on the file suffix.  If only -t/-n are given, the
  103.  * deformatter is forced but string cahracters come from the file suffix.
  104.  * If only -T is given, the deformatter is chosen based on the value
  105.  * given in the -T switch.  Finally, if both -T and -t/-n are given,
  106.  * string characters are controlled by -T and the deformatter by -t/-n.
  107.  *
  108.  * Revision 1.119  1994/03/15  05:58:07  geoff
  109.  * Get rid of a gcc warning
  110.  *
  111.  * Revision 1.118  1994/03/15  05:30:37  geoff
  112.  * Get rid of an unused-variable complaint by proper ifdeffing
  113.  *
  114.  * Revision 1.117  1994/03/12  21:26:48  geoff
  115.  * Correctly limit maximum name lengths for files that have directory paths
  116.  * included.  Also don't use a wired-in 256 for the size of the backup file
  117.  * name.
  118.  *
  119.  * Revision 1.116  1994/02/07  08:10:44  geoff
  120.  * Print GENERATE_LIBRARY_PROTOS in the -vv switch.
  121.  *
  122.  * Revision 1.115  1994/01/26  07:44:47  geoff
  123.  * Make yacc configurable through local.h.
  124.  *
  125.  * Revision 1.114  1994/01/25  07:11:44  geoff
  126.  * Get rid of all old RCS log lines in preparation for the 3.1 release.
  127.  *
  128.  */
  129.  
  130. #include "config.h"
  131. #include "ispell.h"
  132. #include "proto.h"
  133. #include "msgs.h"
  134. #include "version.h"
  135. #include <ctype.h>
  136. #include <sys/stat.h>
  137.  
  138. static void    usage P ((void));
  139. static void    initckch P ((char * wchars));
  140. int        main P ((int argc, char * argv[]));
  141. static void    dofile P ((char * filename));
  142. static void    update_file P ((char * filename, struct stat * statbuf));
  143. static void    expandmode P ((int printorig));
  144.  
  145. static char *    Cmd;
  146. static char *    LibDict = NULL;        /* Pointer to name of $(LIBDIR)/dict */
  147.  
  148. static void usage ()
  149.     {
  150.  
  151.     (void) fprintf (stderr, ISPELL_C_USAGE1, Cmd);
  152.     (void) fprintf (stderr, ISPELL_C_USAGE2, Cmd);
  153.     (void) fprintf (stderr, ISPELL_C_USAGE3, Cmd);
  154.     (void) fprintf (stderr, ISPELL_C_USAGE4, Cmd);
  155.     (void) fprintf (stderr, ISPELL_C_USAGE5, Cmd);
  156.     (void) fprintf (stderr, ISPELL_C_USAGE6, Cmd);
  157.     (void) fprintf (stderr, ISPELL_C_USAGE7, Cmd);
  158.     givehelp (0);
  159.     exit (1);
  160.     }
  161.  
  162. static void initckch (wchars)
  163.     char *        wchars;        /* Characters in -w option, if any */
  164.     {
  165.     register ichar_t    c;
  166.     char        num[4];
  167.  
  168.     for (c = 0; c < (ichar_t) (SET_SIZE + hashheader.nstrchars); ++c)
  169.     {
  170.     if (iswordch (c))
  171.         {
  172.         if (!mylower (c))
  173.         {
  174.         Try[Trynum] = c;
  175.         ++Trynum;
  176.         }
  177.         }
  178.     else if (isboundarych (c))
  179.         {
  180.         Try[Trynum] = c;
  181.         ++Trynum;
  182.         }
  183.     }
  184.     if (wchars != NULL)
  185.     {
  186.     while (Trynum < SET_SIZE  &&  *wchars != '\0')
  187.         {
  188.         if (*wchars != 'n'  &&  *wchars != '\\')
  189.         {
  190.         c = *wchars;
  191.         ++wchars;
  192.         }
  193.         else
  194.         {
  195.         ++wchars;
  196.         num[0] = '\0'; 
  197.         num[1] = '\0'; 
  198.         num[2] = '\0'; 
  199.         num[3] = '\0';
  200.         if (isdigit (wchars[0]))
  201.             {
  202.             num[0] = wchars[0];
  203.             if (isdigit (wchars[1]))
  204.             {
  205.             num[1] = wchars[1];
  206.             if (isdigit (wchars[2]))
  207.                 num[2] = wchars[2];
  208.             }
  209.             }
  210.         if (wchars[-1] == 'n')
  211.             {
  212.             wchars += strlen (num);
  213.             c = atoi (num);
  214.             }
  215.         else
  216.             {
  217.             wchars += strlen (num);
  218.             c = 0;
  219.             if (num[0])
  220.             c = num[0] - '0';
  221.             if (num[1])
  222.             {
  223.             c <<= 3;
  224.             c += num[1] - '0';
  225.             }
  226.             if (num[2])
  227.             {
  228.             c <<= 3;
  229.             c += num[2] - '0';
  230.             }
  231.             }
  232.         }
  233.         c &= NOPARITY;
  234.         if (!hashheader.wordchars[c])
  235.         {
  236.         hashheader.wordchars[c] = 1;
  237.         hashheader.sortorder[c] = hashheader.sortval++;
  238.         Try[Trynum] = c;
  239.         ++Trynum;
  240.         }
  241.         }
  242.     }
  243.     }
  244.  
  245. int main (argc, argv)
  246.     int        argc;
  247.     char *    argv[];
  248.     {
  249.     char *    p;
  250.     char *    cpd;
  251.     char **    versionp;
  252.     char *    wchars = NULL;
  253.     char *    preftype = NULL;
  254.     static char    libdictname[sizeof DEFHASH];
  255.     static char    outbuf[BUFSIZ];
  256.     int        argno;
  257.     int        arglen;
  258.  
  259.     Cmd = *argv;
  260.  
  261.     Trynum = 0;
  262.  
  263.     p = getenv ("DICTIONARY");
  264.     if (p != NULL)
  265.     {
  266.     if (index (p, '/') != NULL)
  267.         (void) strcpy (hashname, p);
  268.     else
  269.         (void) sprintf (hashname, "%s/%s", LIBDIR, p);
  270.     (void) strcpy (libdictname, p);
  271.     p = rindex (p, '.');
  272.     if (p == NULL  ||  strcmp (p, HASHSUFFIX) != 0)
  273.         (void) strcat (hashname, HASHSUFFIX);
  274.     LibDict = rindex (libdictname, '/');
  275.     if (LibDict != NULL)
  276.         LibDict++;
  277.     else
  278.         LibDict = libdictname;
  279.     p = rindex (libdictname, '.');
  280.     if (p != NULL)
  281.         *p = '\0';
  282.     }
  283.     else
  284.     (void) sprintf (hashname, "%s/%s", LIBDIR, DEFHASH);
  285.  
  286.     cpd = NULL;
  287.  
  288.     argv++;
  289.     argc--;
  290.     while (argc && **argv == '-')
  291.     {
  292.     /*
  293.      * Trying to add a new flag?  Can't remember what's been used?
  294.      * Here's a handy guide:
  295.      *
  296.      * Used:
  297.      *
  298.      *    ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
  299.      *    ^^^^       ^^^ ^  ^^ ^^
  300.      *    abcdefghijklmnopqrstuvwxyz
  301.      *    ^^^^^^     ^^^ ^  ^^ ^^^
  302.      */
  303.     arglen = strlen (*argv);
  304.     switch ((*argv)[1])
  305.         {
  306.         case 'v':
  307.         if (arglen > 3)
  308.             usage ();
  309.         for (versionp = Version_ID;  *versionp;  )
  310.             {
  311.             p = *versionp++;
  312.             if (strncmp (p, "(#) ", 5) == 0)
  313.               p += 5;
  314.             (void) printf ("%s\n", p);
  315.             }
  316.         if ((*argv)[2] == 'v')
  317.             {
  318.             (void) printf (ISPELL_C_OPTIONS_ARE);
  319. #ifdef USG
  320.             (void) printf ("\tUSG\n");
  321. #else /* USG */
  322.             (void) printf ("\t!USG (BSD)\n");
  323. #endif /* USG */
  324.             (void) printf ("\tBAKEXT = \"%s\"\n", BAKEXT);
  325.             (void) printf ("\tBINDIR = \"%s\"\n", BINDIR);
  326. #ifdef BOTTOMCONTEXT
  327.             (void) printf ("\tBOTTOMCONTEXT\n");
  328. #else /* BOTTOMCONTEXT */
  329.             (void) printf ("\t!BOTTOMCONTEXT\n");
  330. #endif /* BOTTOMCONTEXT */
  331. #if TERM_MODE == CBREAK
  332.             (void) printf ("\tCBREAK\n");
  333. #endif /* TERM_MODE */
  334.             (void) printf ("\tCC = \"%s\"\n", CC);
  335.             (void) printf ("\tCFLAGS = \"%s\"\n", CFLAGS);
  336. #ifdef COMMANDFORSPACE
  337.             (void) printf ("\tCOMMANDFORSPACE\n");
  338. #else /* COMMANDFORSPACE */
  339.             (void) printf ("\t!COMMANDFORSPACE\n");
  340. #endif /* COMMANDFORSPACE */
  341. #ifdef CONTEXTROUNDUP
  342.             (void) printf ("\tCONTEXTROUNDUP\n");
  343. #else /* CONTEXTROUNDUP */
  344.             (void) printf ("\t!CONTEXTROUNDUP\n");
  345. #endif /* CONTEXTROUNDUP */
  346.             (void) printf ("\tCONTEXTPCT = %d\n", CONTEXTPCT);
  347.             (void) printf ("\tCOUNTSUFFIX = \"%s\"\n", COUNTSUFFIX);
  348.             (void) printf ("\tDEFHASH = \"%s\"\n", DEFHASH);
  349.             (void) printf ("\tDEFINCSTR = \"%s\"\n", DEFINCSTR);
  350.             (void) printf ("\tDEFLANG = \"%s\"\n", DEFLANG);
  351.             (void) printf ("\tDEFNOBACKUPFLAG = %d\n",
  352.               DEFNOBACKUPFLAG);
  353.             (void) printf ("\tDEFPAFF = \"%s\"\n", DEFPAFF);
  354.             (void) printf ("\tDEFPDICT = \"%s\"\n", DEFPDICT);
  355.             (void) printf ("\tDEFTEXFLAG = %d\n", DEFTEXFLAG);
  356.             (void) printf ("\tEGREPCMD = \"%s\"\n", EGREPCMD);
  357.             (void) printf ("\tELISPDIR = \"%s\"\n", ELISPDIR);
  358.             (void) printf ("\tEMACS = \"%s\"\n", EMACS);
  359. #ifdef EQUAL_COLUMNS
  360.             (void) printf ("\tEQUAL_COLUMNS\n");
  361. #else /* EQUAL_COLUMNS */
  362.             (void) printf ("\t!EQUAL_COLUMNS\n");
  363. #endif /* EQUAL_COLUMNS */
  364. #ifdef GENERATE_LIBRARY_PROTOS
  365.             (void) printf ("\tGENERATE_LIBRARY_PROTOS\n");
  366. #else /* GENERATE_LIBRARY_PROTOS */
  367.             (void) printf ("\t!GENERATE_LIBRARY_PROTOS\n");
  368. #endif /* GENERATE_LIBRARY_PROTOS */
  369. #ifdef HAS_RENAME
  370.             (void) printf ("\tHAS_RENAME\n");
  371. #else /* HAS_RENAME */
  372.             (void) printf ("\t!HAS_RENAME\n");
  373. #endif /* HAS_RENAME */
  374.             (void) printf ("\tHASHSUFFIX = \"%s\"\n", HASHSUFFIX);
  375.             (void) printf ("\tHOME = \"%s\"\n", HOME);
  376. #ifdef IGNOREBIB
  377.             (void) printf ("\tIGNOREBIB\n");
  378. #else /* IGNOREBIB */
  379.             (void) printf ("\t!IGNOREBIB\n");
  380. #endif /* IGNOREBIB */
  381.             (void) printf ("\tINCSTRVAR = \"%s\"\n", INCSTRVAR);
  382.             (void) printf ("\tINPUTWORDLEN = %d\n", INPUTWORDLEN);
  383.             (void) printf ("\tLANGUAGES = \"%s\"\n", LANGUAGES);
  384.             (void) printf ("\tLIBDIR = \"%s\"\n", LIBDIR);
  385.             (void) printf ("\tLIBES = \"%s\"\n", LIBES);
  386.             (void) printf ("\tLINT = \"%s\"\n", LINT);
  387.             (void) printf ("\tLINTFLAGS = \"%s\"\n", LINTFLAGS);
  388. #ifndef REGEX_LOOKUP
  389.             (void) printf ("\tLOOK = \"%s\"\n", LOOK);
  390. #endif /* REGEX_LOOKUP */
  391.             (void) printf ("\tMAKE_SORTTMP = \"%s\"\n", MAKE_SORTTMP);
  392.             (void) printf ("\tMALLOC_INCREMENT = %d\n",
  393.               MALLOC_INCREMENT);
  394.             (void) printf ("\tMAN1DIR = \"%s\"\n", MAN1DIR);
  395.             (void) printf ("\tMAN1EXT = \"%s\"\n", MAN1EXT);
  396.             (void) printf ("\tMAN4DIR = \"%s\"\n", MAN4DIR);
  397.             (void) printf ("\tMAN4EXT = \"%s\"\n", MAN4EXT);
  398.             (void) printf ("\tMASKBITS = %d\n", MASKBITS);
  399.             (void) printf ("\tMASKTYPE = %s\n", MASKTYPE_STRING);
  400.             (void) printf ("\tMASKTYPE_WIDTH = %d\n", MASKTYPE_WIDTH);
  401.             (void) printf ("\tMASTERHASH = \"%s\"\n", MASTERHASH);
  402.             (void) printf ("\tMAXAFFIXLEN = %d\n", MAXAFFIXLEN);
  403.             (void) printf ("\tMAXCONTEXT = %d\n", MAXCONTEXT);
  404.             (void) printf ("\tMAXINCLUDEFILES = %d\n",
  405.               MAXINCLUDEFILES);
  406.             (void) printf ("\tMAXNAMLEN = %d\n", MAXNAMLEN);
  407.             (void) printf ("\tMAXPATHLEN = %d\n", MAXPATHLEN);
  408.             (void) printf ("\tMAXPCT = %d\n", MAXPCT);
  409.             (void) printf ("\tMAXSEARCH = %d\n", MAXSEARCH);
  410.             (void) printf ("\tMAXSTRINGCHARLEN = %d\n",
  411.               MAXSTRINGCHARLEN);
  412.             (void) printf ("\tMAXSTRINGCHARS = %d\n", MAXSTRINGCHARS);
  413.             (void) printf ("\tMAX_CAPS = %d\n", MAX_CAPS);
  414.             (void) printf ("\tMAX_HITS = %d\n", MAX_HITS);
  415.             (void) printf ("\tMAX_SCREEN_SIZE = %d\n",
  416.               MAX_SCREEN_SIZE);
  417.             (void) printf ("\tMINCONTEXT = %d\n", MINCONTEXT);
  418. #ifdef MINIMENU
  419.             (void) printf ("\tMINIMENU\n");
  420. #else /* MINIMENU */
  421.             (void) printf ("\t!MINIMENU\n");
  422. #endif /* MINIMENU */
  423.             (void) printf ("\tMINWORD = %d\n", MINWORD);
  424.             (void) printf ("\tMSDOS_BINARY_OPEN = 0x%x\n",
  425.               (unsigned int) MSDOS_BINARY_OPEN);
  426.             (void) printf ("\tMSGLANG = %s\n", MSGLANG);
  427. #ifdef NO_CAPITALIZATION_SUPPORT
  428.             (void) printf ("\tNO_CAPITALIZATION_SUPPORT\n");
  429. #else /* NO_CAPITALIZATION_SUPPORT */
  430.             (void) printf ("\t!NO_CAPITALIZATION_SUPPORT\n");
  431. #endif /* NO_CAPITALIZATION_SUPPORT */
  432. #ifdef NO_STDLIB_H
  433.             (void) printf ("\tNO_STDLIB_H\n");
  434. #else /* NO_STDLIB_H */
  435.             (void) printf ("\t!NO_STDLIB_H (STDLIB_H)\n");
  436. #endif /* NO_STDLIB_H */
  437. #ifdef NO8BIT
  438.             (void) printf ("\tNO8BIT\n");
  439. #else /* NO8BIT */
  440.             (void) printf ("\t!NO8BIT (8BIT)\n");
  441. #endif /* NO8BIT */
  442.             (void) printf ("\tNRSPECIAL = \"%s\"\n", NRSPECIAL);
  443.             (void) printf ("\tOLDPAFF = \"%s\"\n", OLDPAFF);
  444.             (void) printf ("\tOLDPDICT = \"%s\"\n", OLDPDICT);
  445. #ifdef PDICTHOME
  446.             (void) printf ("\tPDICTHOME = \"%s\"\n", PDICTHOME);
  447. #else /* PDICTHOME */
  448.             (void) printf ("\tPDICTHOME = (undefined)\n");
  449. #endif /* PDICTHOME */
  450.             (void) printf ("\tPDICTVAR = \"%s\"\n", PDICTVAR);
  451. #ifdef PIECEMEAL_HASH_WRITES
  452.             (void) printf ("\tPIECEMEAL_HASH_WRITES\n");
  453. #else /* PIECEMEAL_HASH_WRITES */
  454.             (void) printf ("\t!PIECEMEAL_HASH_WRITES\n");
  455. #endif /* PIECEMEAL_HASH_WRITES */
  456. #if TERM_MODE != CBREAK
  457.             (void) printf ("\tRAW\n");
  458. #endif /* TERM_MODE */
  459. #ifdef REGEX_LOOKUP
  460.             (void) printf ("\tREGEX_LOOKUP\n");
  461. #else /* REGEX_LOOKUP */
  462.             (void) printf ("\t!REGEX_LOOKUP\n");
  463. #endif /* REGEX_LOOKUP */
  464.             (void) printf ("\tREGLIB = \"%s\"\n", REGLIB);
  465.             (void) printf ("\tSIGNAL_TYPE = %s\n", SIGNAL_TYPE_STRING);
  466.             (void) printf ("\tSORTPERSONAL = %d\n", SORTPERSONAL);
  467.             (void) printf ("\tSTATSUFFIX = \"%s\"\n", STATSUFFIX);
  468.             (void) printf ("\tTEMPNAME = \"%s\"\n", TEMPNAME);
  469.             (void) printf ("\tTERMLIB = \"%s\"\n", TERMLIB);
  470.             (void) printf ("\tTEXINFODIR = \"%s\"\n", TEXINFODIR);
  471.             (void) printf ("\tTEXSPECIAL = \"%s\"\n", TEXSPECIAL);
  472. #ifdef TRUNCATEBAK
  473.             (void) printf ("\tTRUNCATEBAK\n");
  474. #else /* TRUNCATEBAK */
  475.             (void) printf ("\t!TRUNCATEBAK\n");
  476. #endif /* TRUNCATEBAK */
  477. #ifdef USESH
  478.             (void) printf ("\tUSESH\n");
  479. #else /* USESH */
  480.             (void) printf ("\t!USESH\n");
  481. #endif /* USESH */
  482.             (void) printf ("\tWORDS = \"%s\"\n", WORDS);
  483.             (void) printf ("\tYACC = \"%s\"\n", YACC);
  484.             }
  485.         exit (0);
  486.         break;
  487.         case 'n':
  488.         if (arglen > 2)
  489.             usage ();
  490.         tflag = 0;        /* nroff/troff mode */
  491.         deftflag = 0;
  492.         if (preftype == NULL)
  493.             preftype = "nroff";
  494.         break;
  495.         case 't':            /* TeX mode */
  496.         if (arglen > 2)
  497.             usage ();
  498.         tflag = 1;
  499.         deftflag = 1;
  500.         if (preftype == NULL)
  501.             preftype = "tex";
  502.         break;
  503.         case 'T':            /* Set preferred file type */
  504.         p = (*argv)+2;
  505.         if (*p == '\0')
  506.             {
  507.             argv++; argc--;
  508.             if (argc == 0)
  509.             usage ();
  510.             p = *argv;
  511.             }
  512.         preftype = p;
  513.         break;
  514.         case 'A':
  515.         if (arglen > 2)
  516.             usage ();
  517.         incfileflag = 1;
  518.         aflag = 1;
  519.         break;
  520.         case 'a':
  521.         if (arglen > 2)
  522.             usage ();
  523.         aflag++;
  524.         break;
  525.         case 'D':
  526.         if (arglen > 2)
  527.             usage ();
  528.         dumpflag++;
  529.         nodictflag++;
  530.         break;
  531.         case 'e':
  532.         if (arglen > 3)
  533.             usage ();
  534.         eflag = 1;
  535.         if ((*argv)[2] == 'e')
  536.             eflag = 2;
  537.         else if ((*argv)[2] >= '1'  &&  (*argv)[2] <= '4')
  538.             eflag = (*argv)[2] - '0';
  539.         else if ((*argv)[2] != '\0')
  540.             usage ();
  541.         nodictflag++;
  542.         break;
  543.         case 'c':
  544.         if (arglen > 2)
  545.             usage ();
  546.         cflag++;
  547.         lflag++;
  548.         nodictflag++;
  549.         break;
  550.         case 'b':
  551.         if (arglen > 2)
  552.             usage ();
  553.         xflag = 0;        /* Keep a backup file */
  554.         break;
  555.         case 'x':
  556.         if (arglen > 2)
  557.             usage ();
  558.         xflag = 1;        /* Don't keep a backup file */
  559.         break;
  560.         case 'f':
  561.         fflag++;
  562.         p = (*argv)+2;
  563.         if (*p == '\0')
  564.             {
  565.             argv++; argc--;
  566.             if (argc == 0)
  567.             usage ();
  568.             p = *argv;
  569.             }
  570.         askfilename = p;
  571.         if (*askfilename == '\0')
  572.             askfilename = NULL;
  573.         break;
  574.         case 'L':
  575.         p = (*argv)+2;
  576.         if (*p == '\0')
  577.             {
  578.             argv++; argc--;
  579.             if (argc == 0)
  580.             usage ();
  581.             p = *argv;
  582.             }
  583.         contextsize = atoi (p);
  584.         break;
  585.         case 'l':
  586.         if (arglen > 2)
  587.             usage ();
  588.         lflag++;
  589.         break;
  590. #ifndef USG
  591.         case 's':
  592.         if (arglen > 2)
  593.             usage ();
  594.         sflag++;
  595.         break;
  596. #endif
  597.         case 'S':
  598.         if (arglen > 2)
  599.             usage ();
  600.         sortit = 0;
  601.         break;
  602.         case 'B':        /* -B:  report missing blanks */
  603.         if (arglen > 2)
  604.             usage ();
  605.         compoundflag = COMPOUND_NEVER;
  606.         break;
  607.         case 'C':        /* -C:  compound words are acceptable */
  608.         if (arglen > 2)
  609.             usage ();
  610.         compoundflag = COMPOUND_ANYTIME;
  611.         break;
  612.         case 'P':        /* -P:  don't gen non-dict poss's */
  613.         if (arglen > 2)
  614.             usage ();
  615.         tryhardflag = 0;
  616.         break;
  617.         case 'm':        /* -m:  make all poss affix combos */
  618.         if (arglen > 2)
  619.             usage ();
  620.         tryhardflag = 1;
  621.         break;
  622.         case 'N':        /* -N:  suppress minimenu */
  623.         if (arglen > 2)
  624.             usage ();
  625.         minimenusize = 0;
  626.         break;
  627.         case 'M':        /* -M:  force minimenu */
  628.         if (arglen > 2)
  629.             usage ();
  630.         minimenusize = 2;
  631.         break;
  632.         case 'p':
  633.         cpd = (*argv)+2;
  634.         if (*cpd == '\0')
  635.             {
  636.             argv++; argc--;
  637.             if (argc == 0)
  638.             usage ();
  639.             cpd = *argv;
  640.             if (*cpd == '\0')
  641.             cpd = NULL;
  642.             }
  643.         LibDict = NULL;
  644.         break;
  645.         case 'd':
  646.         p = (*argv)+2;
  647.         if (*p == '\0')
  648.             {
  649.             argv++; argc--;
  650.             if (argc == 0)
  651.             usage ();
  652.             p = *argv;
  653.             }
  654.         if (index (p, '/') != NULL)
  655.             (void) strcpy (hashname, p);
  656.         else
  657.             (void) sprintf (hashname, "%s/%s", LIBDIR, p);
  658.         if (cpd == NULL  &&  *p != '\0')
  659.             LibDict = p;
  660.         p = rindex (p, '.');
  661.         if (p != NULL  &&  strcmp (p, HASHSUFFIX) == 0)
  662.             *p = '\0';    /* Don't want ext. in LibDict */
  663.         else
  664.             (void) strcat (hashname, HASHSUFFIX);
  665.         if (LibDict != NULL)
  666.             {
  667.             p = rindex (LibDict, '/');
  668.             if (p != NULL)
  669.             LibDict = p + 1;
  670.             }
  671.         break;
  672.         case 'V':        /* Display 8-bit characters as M-xxx */
  673.         if (arglen > 2)
  674.             usage ();
  675.         vflag = 1;
  676.         break;
  677.         case 'w':
  678.         wchars = (*argv)+2;
  679.         if (*wchars == '\0')
  680.             {
  681.             argv++; argc--;
  682.             if (argc == 0)
  683.             usage ();
  684.             wchars = *argv;
  685.             }
  686.         break;
  687.         case 'W':
  688.         if ((*argv)[2] == '\0')
  689.             {
  690.             argv++; argc--;
  691.             if (argc == 0)
  692.             usage ();
  693.             minword = atoi (*argv);
  694.             }
  695.         else
  696.             minword = atoi (*argv + 2);
  697.         break;
  698.         default:
  699.         usage ();
  700.         }
  701.     argv++;
  702.     argc--;
  703.     }
  704.  
  705.     if (!argc  &&  !lflag  &&  !aflag   &&  !eflag  &&  !dumpflag)
  706.     usage ();
  707.  
  708.     /*
  709.      * Because of the high cost of reading the dictionary, we stat
  710.      * the files specified first to see if they exist.  If at least
  711.      * one exists, we continue.
  712.      */
  713.     for (argno = 0;  argno < argc;  argno++)
  714.     {
  715.     if (access (argv[argno], 4) >= 0)
  716.         break;
  717.     }
  718.     if (argno >= argc  &&  !lflag  &&  !aflag  &&  !eflag  &&  !dumpflag)
  719.     {
  720.     (void) fprintf (stderr,
  721.       argc == 1 ? ISPELL_C_NO_FILE : ISPELL_C_NO_FILES);
  722.     exit (1);
  723.     }
  724.     if (linit () < 0)
  725.     exit (1);
  726.  
  727.     if (preftype != NULL)
  728.     {
  729.     prefstringchar =
  730.       findfiletype (preftype, 1, deftflag < 0 ? &deftflag : (int *) NULL);
  731.     if (prefstringchar < 0
  732.       &&  strcmp (preftype, "tex") != 0
  733.       &&  strcmp (preftype, "nroff") != 0)
  734.         {
  735.         (void) fprintf (stderr, ISPELL_C_BAD_TYPE, preftype);
  736.         exit (1);
  737.         }
  738.     }
  739.     if (prefstringchar < 0)
  740.     defdupchar = 0;
  741.     else
  742.     defdupchar = prefstringchar;
  743.  
  744.     if (compoundflag < 0)
  745.     compoundflag = hashheader.compoundflag;
  746.     if (tryhardflag < 0)
  747.     tryhardflag = hashheader.defhardflag;
  748.  
  749.     initckch(wchars);
  750.  
  751.     if (LibDict == NULL)    
  752.     {
  753.     (void) strcpy (libdictname, DEFHASH);
  754.     LibDict = libdictname;
  755.     p = rindex (libdictname, '.');
  756.     if (p != NULL  &&  strcmp (p, HASHSUFFIX) == 0)
  757.         *p = '\0';    /* Don't want ext. in LibDict */
  758.     }
  759.     if (!nodictflag)
  760.     treeinit (cpd, LibDict);
  761.  
  762.     if (aflag)
  763.     {
  764.     askmode ();
  765.     treeoutput ();
  766.     exit (0);
  767.     }
  768.     else if (eflag)
  769.     {
  770.     expandmode (eflag);
  771.     exit (0);
  772.     }
  773.     else if (dumpflag)
  774.     {
  775.     dumpmode ();
  776.     exit (0);
  777.     }
  778.  
  779. #ifndef __bsdi__
  780.     setbuf (stdout, outbuf);
  781. #endif /* __bsdi__ */
  782.     if (lflag)
  783.     {
  784.     infile = stdin;
  785.     outfile = stdout;
  786.     checkfile ();
  787.     exit (0);
  788.     }
  789.  
  790.     terminit ();
  791.  
  792.     while (argc--)
  793.     dofile (*argv++);
  794.  
  795.     done (0);
  796.     /* NOTREACHED */
  797.     return 0;
  798.     }
  799.  
  800. static void dofile (filename)
  801.     char *    filename;
  802.     {
  803.     struct stat    statbuf;
  804.     char *    cp;
  805.  
  806.     currentfile = filename;
  807.  
  808.     /* See if the file is a .tex file.  If so, set the appropriate flags. */
  809.     tflag = deftflag;
  810.     if (tflag < 0)
  811.     tflag =
  812.       (cp = rindex (filename, '.')) != NULL  &&  strcmp (cp, ".tex") == 0;
  813.  
  814.     if (prefstringchar < 0)
  815.     {
  816.     defdupchar =
  817.       findfiletype (filename, 0, deftflag < 0 ? &tflag : (int *) NULL);
  818.     if (defdupchar < 0)
  819.         defdupchar = 0;
  820.     }
  821.  
  822.     if ((infile = fopen (filename, "r")) == NULL)
  823.     {
  824.     (void) fprintf (stderr, CANT_OPEN, filename);
  825.     (void) sleep ((unsigned) 2);
  826.     return;
  827.     }
  828.  
  829.     readonly = access (filename, 2) < 0;
  830.     if (readonly)
  831.     {
  832.     (void) fprintf (stderr, ISPELL_C_CANT_WRITE, filename);
  833.     (void) sleep ((unsigned) 2);
  834.     }
  835.  
  836.     (void) fstat (fileno (infile), &statbuf);
  837.     (void) strcpy (tempfile, TEMPNAME);
  838.     if (mktemp (tempfile) == NULL  ||  tempfile[0] == '\0'
  839.       ||  (outfile = fopen (tempfile, "w")) == NULL)
  840.     {
  841.     (void) fprintf (stderr, CANT_CREATE,
  842.       (tempfile == NULL  ||  tempfile[0] == '\0')
  843.         ? "temporary file" : tempfile);
  844.     (void) sleep ((unsigned) 2);
  845.     return;
  846.     }
  847.     (void) chmod (tempfile, statbuf.st_mode);
  848.  
  849.     quit = 0;
  850.     changes = 0;
  851.  
  852.     checkfile ();
  853.  
  854.     (void) fclose (infile);
  855.     (void) fclose (outfile);
  856.  
  857.     if (!cflag)
  858.     treeoutput ();
  859.  
  860.     if (changes && !readonly)
  861.     update_file (filename, &statbuf);
  862.     (void) unlink (tempfile);
  863.     }
  864.  
  865. static void update_file (filename, statbuf)
  866.     char *        filename;
  867.     struct stat *    statbuf;
  868.     {
  869.     char        bakfile[MAXPATHLEN];
  870.     int            c;
  871.     char *        pathtail;
  872.  
  873.     if ((infile = fopen (tempfile, "r")) == NULL)
  874.     {
  875.     (void) fprintf (stderr, ISPELL_C_TEMP_DISAPPEARED, tempfile);
  876.     (void) sleep ((unsigned) 2);
  877.     return;
  878.     }
  879.  
  880. #ifdef TRUNCATEBAK
  881.     (void) strncpy (bakfile, filename, sizeof bakfile - 1);
  882.     bakfile[sizeof bakfile - 1] = '\0';
  883.     if (strcmp(BAKEXT, filename + strlen(filename) - sizeof BAKEXT - 1) != 0)
  884.     {
  885.     pathtail = rindex (bakfile, '/');
  886.     if (pathtail == NULL)
  887.         pathtail = bakfile;
  888.     else
  889.         pathtail++;
  890.     if (strlen (pathtail) > MAXNAMLEN - sizeof BAKEXT - 1)
  891.         pathtail[MAXNAMLEN - sizeof BAKEXT -1] = '\0';
  892.     (void) strcat (pathtail, BAKEXT);
  893.     }
  894. #else
  895.     (void) sprintf (bakfile, "%.*s%s", (int) (sizeof bakfile - sizeof BAKEXT),
  896.       filename, BAKEXT);
  897. #endif
  898.  
  899.     pathtail = rindex (bakfile, '/');
  900.     if (pathtail == NULL)
  901.     pathtail = bakfile;
  902.     else
  903.     pathtail++;
  904.     if (strncmp (filename, bakfile, pathtail - bakfile + MAXNAMLEN) != 0)
  905.     (void) unlink (bakfile);    /* unlink so we can write a new one. */
  906. #ifdef HAS_RENAME
  907.     (void) rename (filename, bakfile);
  908. #else /* HAS_RENAME */
  909.     if (link (filename, bakfile) == 0)
  910.     (void) unlink (filename);
  911. #endif /* HAS_RENAME */
  912.  
  913.     /* if we can't write new, preserve .bak regardless of xflag */
  914.     if ((outfile = fopen (filename, "w")) == NULL)
  915.     {
  916.     (void) fprintf (stderr, CANT_CREATE, filename);
  917.     (void) sleep ((unsigned) 2);
  918.     return;
  919.     }
  920.  
  921.     (void) chmod (filename, statbuf->st_mode);
  922.  
  923.     while ((c = getc (infile)) != EOF)
  924.     (void) putc (c, outfile);
  925.  
  926.     (void) fclose (infile);
  927.     (void) fclose (outfile);
  928.  
  929.     if (xflag
  930.       &&  strncmp (filename, bakfile, pathtail - bakfile + MAXNAMLEN) != 0)
  931.     (void) unlink (bakfile);
  932.     }
  933.  
  934. static void expandmode (option)
  935.     int            option;        /* How to print: */
  936.                     /* 1 = expansions only */
  937.                     /* 2 = original line + expansions */
  938.                     /* 3 = original paired w/ expansions */
  939.                     /* 4 = add length ratio */
  940.     {
  941.     char        buf[BUFSIZ];
  942.     int            explength;    /* Total length of all expansions */
  943.     register char *    flagp;        /* Pointer to next flag char */
  944.     ichar_t        ibuf[BUFSIZ];
  945.     MASKTYPE        mask[MASKSIZE];
  946.     char        origbuf[BUFSIZ]; /* Original contents of buf */
  947.     char        ratiobuf[20];    /* Expansion/root length ratio */
  948.     int            rootlength;    /* Length of root word */
  949.     register int    temp;
  950.  
  951.     while (xgets (buf, sizeof buf, stdin) != NULL)
  952.     {
  953.     rootlength = strlen (buf);
  954.     if (buf[rootlength - 1] == '\n')
  955.       buf[--rootlength] = '\0';
  956.     (void) strcpy (origbuf, buf);
  957.     if ((flagp = index (buf, hashheader.flagmarker)) != NULL)
  958.         {
  959.         rootlength = flagp - buf;
  960.         *flagp++ = '\0';
  961.         }
  962.     if (option == 2  ||  option == 3  ||  option == 4)
  963.         (void) printf ("%s ", origbuf);
  964.     if (flagp != NULL)
  965.         {
  966.         if (flagp - buf > INPUTWORDLEN)
  967.         buf[INPUTWORDLEN] = '\0';
  968.         }
  969.     else
  970.         {
  971.         if ((int) strlen (buf) > INPUTWORDLEN - 1)
  972.         buf[INPUTWORDLEN] = '\0';
  973.         }
  974.     (void) fputs (buf, stdout);
  975.     if (flagp != NULL)
  976.         {
  977.         (void) bzero ((char *) mask, sizeof (mask));
  978.         while (*flagp != '\0'  &&  *flagp != '\n')
  979.         {
  980.         temp = CHARTOBIT ((unsigned char) *flagp);
  981.         if (temp >= 0  &&  temp <= LARGESTFLAG)
  982.             SETMASKBIT (mask, temp);
  983.         else
  984.             (void) fprintf (stderr, BAD_FLAG, (unsigned char) *flagp);
  985.         flagp++;
  986.         /* Accept old-format dicts with extra slashes */
  987.         if (*flagp == hashheader.flagmarker)
  988.             flagp++;
  989.         }
  990.         if (strtoichar (ibuf, buf, sizeof ibuf, 1))
  991.         (void) fprintf (stderr, WORD_TOO_LONG (buf));
  992.         explength = expand_pre (origbuf, ibuf, mask, option, "");
  993.         explength += expand_suf (origbuf, ibuf, mask, 0, option, "");
  994.         explength += rootlength;
  995.         if (option == 4)
  996.         {
  997.         (void) sprintf (ratiobuf, " %f",
  998.           (double) explength / (double) rootlength);
  999.         (void) fputs (ratiobuf, stdout);
  1000.         (void) expand_pre (origbuf, ibuf, mask, 3, ratiobuf);
  1001.         (void) expand_suf (origbuf, ibuf, mask, 0, 3, ratiobuf);
  1002.         }
  1003.         }
  1004.     (void) putchar ('\n');
  1005.     }
  1006.     }
  1007.